package com.qd.panda.mq.charge;

import cn.hutool.core.math.Money;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.DateUtil;
import com.cdqidi.util.RedissonLockTemplate;
import com.cdqidi.util.SpringContextHolder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.plate.PlateDTO;
import com.qd.common.panda.domain.entity.stroke.UserStrokeDTO;
import com.qd.common.panda.domain.entity.stroke.UserStrokeOrderChargeDTO;
import com.qd.common.panda.domain.entity.stroke.UserStrokeOrderDTO;
import com.qd.common.panda.event.EtcPayEvent;
import com.qd.common.sys.domain.entity.log.ReceiveLogDTO;
import com.qd.common.sys.event.ReceiveLogEvent;
import com.qd.panda.dc.DcService;
import com.qd.panda.dc.dto.CarInOutDTO;
import com.qd.panda.dc.dto.ChargeStatusDTO;
import com.qd.panda.dc.dto.DcOrderDTO;
import com.qd.panda.dc.dto.PayInfoDTO;
import com.qd.panda.dc.dto.charge.ChargeActionReqDTO;
import com.qd.panda.dc.dto.charge.StatusChargeRespDTO;
import com.qd.panda.model.*;
import com.qd.panda.mq.bo.ChargeBO;
import com.qd.panda.service.park.CarParkService;
import com.qd.panda.service.plate.PlateService;
import com.qd.panda.service.plate.UserPlateRelationService;
import com.qd.panda.service.stroke.DisplayUtil;
import com.qd.panda.service.stroke.UserStrokeHolderService;
import com.qd.panda.service.stroke.UserStrokeService;
import com.qd.panda.service.stroke.order.UserStrokeOrderChargeService;
import com.qd.panda.service.stroke.order.UserStrokeOrderService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 充电的相关操作
 *
 * @author sjk
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class ChargeConsumerService {
    private final CarParkService carParkService;
    private final DcService dcService;
    private final UserPlateRelationService userPlateRelationService;
    private final UserStrokeService userStrokeService;
    private final UserStrokeOrderService userStrokeOrderService;
    private final UserStrokeHolderService userStrokeHolderService;
    private final UserStrokeOrderChargeService userStrokeOrderChargeService;
    private final ObjectMapper objectMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final PlateService plateService;

    @Autowired
    @Qualifier("strokeThreadPoolExecutor")
    private ThreadPoolExecutor threadPoolExecutor;

    @Transactional(rollbackFor = Exception.class)
    public void doProcess(String json) {
        if (log.isDebugEnabled()) {
            log.debug("充电信息推送: {}", json);
        }
        LocalDateTime now = LocalDateTime.now();
        ReceiveLogDTO receiveLog = new ReceiveLogDTO();
        receiveLog.setContent(json);
        receiveLog.setAddTime(now);
        String errMsg = null;
        ChargeBO chargeBO = null;
        String sid = null;
        boolean etcPay = false;
        try {
            try {
                chargeBO = objectMapper.readValue(json, ChargeBO.class);
                checkParams(chargeBO);
                //为空的时候认为是插枪状态，此时创建订单
                Integer startChargeSeqStat = Optional.ofNullable(chargeBO.getStartChargeSeqStat()).orElse(-1);
                if (chargeBO.getStatus().equals(2)) {
                    //说明是把枪状态，此时需要删除行程
                    startChargeSeqStat = 5;
                }
                chargeBO.setStartChargeSeqStat(startChargeSeqStat);
                //1：启动中,2：充电中,3：停止中,4：已结束,5：未知
                switch (startChargeSeqStat) {
                    case -1:
                    case 1:
                    case 2:
                        startCharge(chargeBO);
                        break;
                    case 3:
                        log.info("充电停止中,不处理,车牌号: {},订单号: {}", chargeBO.getPlateNumber(), chargeBO.getStartChargeSeq());
                        break;
                    case 4:
                        sid = stopCharge(chargeBO);
                        etcPay = ConstantDto.SF1.equals(plateService.etcPay(chargeBO.getPlateNumber()));
                        break;
                    case 5:
                        deleteCharge(chargeBO);
                        break;
                    default:
                        throw new ApiException("异常状态不处理,startChargeSeqStat： " + startChargeSeqStat);
                }
            } catch (Exception e) {
                log.error("", e);
                errMsg = e.getMessage();
            }
        } finally {
            //记录日志
            if (null != errMsg) {
                receiveLog.setErrMsg(errMsg);
            }
            receiveLog.setLogType(PandaConstant.LOG_TYPE_CHARGE);
            SpringContextHolder.publishEvent(new ReceiveLogEvent(receiveLog));
        }
        ChargeBO finalChargeBO = chargeBO;
        String finalSid = sid;
        boolean finalEtcPay = etcPay;
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCompletion(int status) {
                if (log.isDebugEnabled()) {
                    log.debug("sid: {},是否支持ETC支付: {}", finalSid, finalEtcPay);
                }
                if (TransactionSynchronization.STATUS_COMMITTED == status) {
                    if (finalEtcPay && finalChargeBO.getStartChargeSeqStat().equals(4)) {
                        if (log.isDebugEnabled()) {
                            log.debug("处理充电结束成功,开始ETC支付,plateNumber: {},充电总金额: {},行程ID： {}", finalChargeBO.getPlateNumber(), finalChargeBO.getTotalMoney(), finalSid);
                        }
                        SpringContextHolder.publishEvent(new EtcPayEvent(finalSid));
                    }
                }
            }
        });
    }


    @Transactional(rollbackFor = Exception.class)
    public void deleteCharge(ChargeBO chargeBO) {
        String plateNumber = chargeBO.getPlateNumber();
        String parkingId = chargeBO.getParkingId();
        UserStrokeDTO query = new UserStrokeDTO();
        query.setPlateNumber(plateNumber);
        query.setParkId(parkingId);
        query.setTripType(DisplayUtil.TRIP_TYPE_1);
        final UserStroke userStroke = userStrokeService.getProcessStroke(query);
        if (null != userStroke) {
            List<UserStrokeOrderDTO> orderList = userStrokeOrderService.getListBySid(userStroke.getSid());
            if (!orderList.isEmpty()) {
                Iterator<UserStrokeOrderDTO> iterator = orderList.iterator();
                while (iterator.hasNext()) {
                    UserStrokeOrderDTO userStrokeOrderDTO = iterator.next();
                    UserStrokeOrderCharge userStrokeOrderCharge = userStrokeOrderChargeService.getById(userStrokeOrderDTO.getOrderId());
                    //只有未充电的订单才删除，说明是插了枪又拔了，没有充电动作
                    if (null != userStrokeOrderCharge && userStrokeOrderCharge.getState().equals(DisplayUtil.CHARGE_STAT_0)) {
                        userStrokeOrderChargeService.removeById(userStrokeOrderCharge.getOrderId());
                        userStrokeOrderService.removeById(userStrokeOrderDTO.getOrderId());
                        userStrokeOrderCharge.freeData();
                        iterator.remove();
                    }
                }
            }
            if (orderList.isEmpty()) {
                //说明订单都不存在了，那么删除行程
                userStrokeService.removeById(userStroke.getSid());
                userStroke.freeData();
            }
        }
    }

    private void checkParams(ChargeBO chargeBO) {
        if (!StringUtils.hasText(chargeBO.getPlateNumber())) {
            throw new ApiException("车牌号为空");
        }
        if (!StringUtils.hasText(chargeBO.getParkingId())) {
            throw new ApiException("停车场编号为空");
        }
//        if (!StringUtils.hasText(chargeBO.getStartChargeSeq())) {
//            throw new ApiException("订单编号为空");
//        }
    }

    /**
     * 插抢开始充电,目前增加一种情况，插枪需要用户手工确认了才能开始充电
     *
     * @param chargeBO 充电信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void startCharge(ChargeBO chargeBO) {
        final CarPark carPark = carParkService.getById(chargeBO.getParkingId());
        if (null == carPark) {
            throw new ApiException(MessageFormat.format("停车场ID不存在,parkId: {0}", chargeBO.getParkingId()));
        }
        final UserPlateRelation userPlateRelation = userPlateRelationService.getUniqueByPlateNumber(chargeBO.getPlateNumber());
        if (null == userPlateRelation) {
            throw new ApiException(MessageFormat.format("当前车牌号没有对应的人员信息,plateNumber: {0}", chargeBO.getPlateNumber()));
        }
        final PlateDTO plate = plateService.getByIdDto(chargeBO.getPlateNumber());
        if (null == plate) {
            throw new ApiException(MessageFormat.format("当前车牌号在系统中不存在: {0}", chargeBO.getPlateNumber()));
        }
        //if (plate.getCarType().equals(CarTypeEnum.FUEL_CAR.getCode())) {
        //    throw new ApiException(MessageFormat.format("燃油车不支持充电,不处理: {0}", chargeBO.getPlateNumber()));
        //}
//        final DcOrderDTO chargeOrder = dcService.getChargeOrder(chargeBO.getStartChargeSeq());
//        if (null == chargeOrder) {
//            throw new ApiException(MessageFormat.format("查询不到充电订单信息,chargeOrder: {0}", chargeBO.getStartChargeSeq()));
//        }
        UserStrokeDTO query = new UserStrokeDTO();
        query.setUserId(userPlateRelation.getUserId());
        final UserStroke userStroke = userStrokeService.getProcessStroke(query);
        query.freeData();
        String sid;
        if (null == userStroke) {
            //创建行程
            sid = createStroke(chargeBO, userPlateRelation);
        } else {
            sid = userStroke.getSid();
            query.freeData();
        }
        LocalDateTime startTime;
        if (StringUtils.hasLength(chargeBO.getStartTime())) {
            startTime = DateUtil.strToLocalDateTime(chargeBO.getStartTime());
        } else {
            startTime = LocalDateTime.now();
        }
        //创建订单
        //订单可能存在更新的情况，（充电订单状态:1：启动中,2：充电中,3：停止中,4：已结束,5：未知），如果启动中就推送通知，很有可能没有订单编号和充电开始时间，所以只能等到充电中，才能获得相关信息进行更新

        UserStrokeOrder userStrokeOrder = null;
        if (StringUtils.hasLength(chargeBO.getStartChargeSeq())) {
            userStrokeOrder = userStrokeOrderService.getUniqueByThirdPartyOrderId(chargeBO.getStartChargeSeq());
        } else {
            if (chargeBO.getStartChargeSeqStat().equals(DisplayUtil.CHARGE_STAT_0)) {
                //说明订单是等待确认的订单，此时查询是否存在
                userStrokeOrder = userStrokeOrderService.dtoToModel(userStrokeOrderService.getBaseMapper().getUserStrokeByState(userPlateRelation.getUserId(), chargeBO.getParkingId()));
            }
        }
        if (null == userStrokeOrder) {
            //充电订单
            String orderId = IdWorker.getIdStr();
            UserStrokeOrderChargeDTO userStrokeOrderCharge = new UserStrokeOrderChargeDTO();
            userStrokeOrderCharge.setSid(sid);
            userStrokeOrderCharge.setOrderId(orderId);
            buildUserStrokeOrderCharge(chargeBO, userStrokeOrderCharge);

            //订单主表
//            final String nickname = Optional.ofNullable(middleUserService.getUniqueByUserIdAndAppId(userPlateRelation.getUserId(), parkConfigDTO.getDefaultMiniProgramAppId())).map(MiddleUser::getNickName).orElse(null);
            userStrokeHolderService.createStrokeOrder(sid, orderId, carPark.getPId(), chargeBO.getPlateNumber(), userStrokeOrderCharge.getTotalAmount(), DisplayUtil.ORDER_TYPE_3, DisplayUtil.PAY_STATUS_0, plateService.etcPay(chargeBO.getPlateNumber()), DisplayUtil.TRIP_TYPE_1, userPlateRelation.getUserId(), null, startTime, null, chargeBO.getStartChargeSeq(), null);
            //充电订单
            userStrokeOrderChargeService.save(userStrokeOrderCharge);
            userStrokeOrderCharge.freeData();
        } else {
            UserStrokeOrderChargeDTO userStrokeOrderCharge = userStrokeOrderChargeService.getByIdDto(userStrokeOrder.getOrderId());
            if (null != userStrokeOrderCharge) {
                buildUserStrokeOrderCharge(chargeBO, userStrokeOrderCharge);
                userStrokeOrderChargeService.update(userStrokeOrderCharge);
                userStrokeOrderCharge.freeData();
            }
            boolean isUpdate = false;
            if (null != startTime) {
                userStrokeOrder.setStartTime(startTime);
                isUpdate = true;
            }
            if (StringUtils.hasLength(chargeBO.getStartChargeSeq())) {
                userStrokeOrder.setThirdPartyOrderId(chargeBO.getStartChargeSeq());
                isUpdate = true;
            }
            if (isUpdate) {
                final UserStrokeOrderDTO userStrokeOrderDTO = userStrokeOrderService.modelToDto(userStrokeOrder);
                userStrokeOrderService.update(userStrokeOrderDTO);
                userStrokeOrderDTO.freeData();
            }
            userStrokeOrder.freeData();
        }
        carPark.freeData();
        userPlateRelation.freeData();
    }

    private String createStroke(ChargeBO chargeBO, UserPlateRelation userPlateRelation) {
        String sid = IdWorker.getIdStr();
        LocalDateTime inTime = null;
        if (chargeBO.getStartChargeSeqStat().equals(-1)) {
            //只是有了插枪动作，需要查询入场信息
            final CarInOutDTO carInOut = dcService.getCarInOut(chargeBO.getParkingId(), chargeBO.getPlateNumber(), null, null, true, "in");
            log.info("查询进出场记录,carInOut: {}", carInOut);
            if (null != carInOut) {
                final List<CarInOutDTO.In> inList = carInOut.getIn();
                if (null != inList && !inList.isEmpty()) {
                    final CarInOutDTO.In in = inList.get(0);
                    if (null != in) {
                        inTime = DateUtil.strToLocalDateTime(in.getInTime());
                    }
                }
            }
        }
        //创建行程
        final UserStrokeDTO userStrokeDTO = userStrokeHolderService.createUserStroke(sid, chargeBO.getParkingId(), chargeBO.getPlateNumber(), DisplayUtil.TRIP_TYPE_1, null, userPlateRelation.getUserId(), BigDecimal.valueOf(0D), DisplayUtil.PROCESS_STATUS_3);
        if (null == inTime) {
            inTime = LocalDateTime.now();
        }
        userStrokeDTO.setStartTime(inTime);
        userStrokeDTO.setIntoTime(inTime);
        userStrokeDTO.setBillStartTime(inTime);
        userStrokeService.save(userStrokeDTO);
        userStrokeDTO.freeData();
        return sid;
    }

    private void buildUserStrokeOrderCharge(ChargeBO chargeBO, UserStrokeOrderChargeDTO userStrokeOrderCharge) {
        if (null != chargeBO.getTotalMoney()) {
            userStrokeOrderCharge.setTotalAmount(new Money(chargeBO.getTotalMoney()).getAmount());
        }
        if (null != chargeBO.getTotalElecMoney()) {
            userStrokeOrderCharge.setElectricityFee(new Money(chargeBO.getTotalElecMoney()).getAmount());
        }
        if (null != chargeBO.getTotalPower()) {
            userStrokeOrderCharge.setChargeCapacity(new Money(chargeBO.getTotalPower()).getAmount());
        }
        if (null != chargeBO.getTotalSeviceMoney()) {
            userStrokeOrderCharge.setServiceCharge(new Money(chargeBO.getTotalSeviceMoney()).getAmount());
        }
        if (null != chargeBO.getStartChargeSeqStat()) {
            userStrokeOrderCharge.setState(chargeBO.getStartChargeSeqStat());
        }
        if (StringUtils.hasLength(chargeBO.getConnectorID())) {
            userStrokeOrderCharge.setConnectorID(chargeBO.getConnectorID());
        }
        if (null != chargeBO.getSoc()) {
            userStrokeOrderCharge.setSoc(chargeBO.getSoc());
        }
        if (StringUtils.hasLength(chargeBO.getOperatorID())) {
            userStrokeOrderCharge.setOperatorID(chargeBO.getOperatorID());
        }
    }


    /**
     * 拔枪停止充电,已结束
     *
     * @param chargeBO 充电信息
     * @return sid 行程ID
     */
    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public String stopCharge(ChargeBO chargeBO) {
        final UserPlateRelation userPlateRelation = Optional.ofNullable(userPlateRelationService.getUniqueByPlateNumber(chargeBO.getPlateNumber())).orElseThrow(() -> new ApiException(MessageFormat.format("当前车牌号没有对应的人员信息,plateNumber: {0}", chargeBO.getPlateNumber())));
        userPlateRelation.freeData();

        final UserStrokeOrder userStrokeOrder = Optional.ofNullable(userStrokeOrderService.getUniqueByThirdPartyOrderId(chargeBO.getStartChargeSeq())).orElseThrow(() -> new ApiException(MessageFormat.format("订单不存在,thirdPartyOrderId: {0}", chargeBO.getStartChargeSeq())));
        String sid = userStrokeOrder.getSid();

        //读取出行程以后，需要根据订单计算总的费用
        final UserStrokeDTO userStroke = Optional.ofNullable(userStrokeService.getByIdDto(sid)).orElseThrow(() -> new ApiException(MessageFormat.format("行程不存在,sid: {0}", sid)));
        userStroke.setPayAmount(new BigDecimal(0));

        //final CompletableFuture<DcOrderDTO> chargeOrder = getChargeOrder(chargeBO.getStartChargeSeq());

        String key = EtcPayService.getPayProcessKey(sid);
        RedissonLockTemplate.execute(sid, () -> {
            log.info("key:{},exists: {},value: {}", key, stringRedisTemplate.hasKey(key), stringRedisTemplate.opsForValue().get(key));
            if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))) {
                throw new ApiException(MessageFormat.format("当前行程正在支付,取消结束充电计费操作,sid: {0}", sid));
            }
            //try {
            //Optional.ofNullable(chargeOrder.get()).ifPresent(dcOrderDTO -> {
            //之前设计是重新调用接口查询充电费用，现在改为按接收数据操作
            DcOrderDTO dcOrderDTO = buildChargeBoToDcOrderDTO(chargeBO);
            updateUserStrokeOrderCharge(dcOrderDTO, userStrokeOrder, userStroke);
            dcOrderDTO.freeData();
            //});
            //} catch (InterruptedException e) {
            //    Thread.currentThread().interrupt();
            //    throw new ApiException(e);
            //} catch (ExecutionException e) {
            //    throw new ApiException(e);
            //}
            userStroke.setAmount(userStroke.getPayAmount());
            userStroke.setOnLinePayAmount(userStroke.getPayAmount());
            userStrokeService.update(userStroke);
            userStroke.freeData();
            return null;
        }, -1);
        userStrokeOrder.freeData();
        return sid;
    }


    /**
     * 获得停车订单
     *
     * @param parkId      停车场ID
     * @param plateNumber 车牌号
     * @param sid         行程ID
     * @return 停车订单
     */
    public CompletableFuture<PayInfoDTO> getParkOrder(String parkId, String plateNumber, String sid) {
        return CompletableFuture.supplyAsync(() -> {
            final Integer freeTime = userStrokeOrderService.getFreeTime(parkId, sid);
            return dcService.queryPay(parkId, plateNumber, Long.valueOf(freeTime));
        }, threadPoolExecutor);
    }

    /**
     * 获得充电订单
     *
     * @param startChargeSeq 充电订单号
     * @return 充电订单
     */
    private CompletableFuture<StatusChargeRespDTO> getChargeOrder(String parkId, String startChargeSeq, String connectorId, String operatorId) {
        return CompletableFuture.supplyAsync(() -> {
            final ChargeActionReqDTO chargeActionReqDTO = new ChargeActionReqDTO().setAction(ChargeActionReqDTO.ACTION_STATUS).setStartChargeSeq(startChargeSeq).setConnectorID(connectorId).setOperatorID(operatorId);
            StatusChargeRespDTO statusCharge = dcService.statusCharge(parkId, chargeActionReqDTO);
            chargeActionReqDTO.freeData();
            if (null == statusCharge) {
                log.error("查询不到充电订单信息,chargeOrder: {}", startChargeSeq);
                return null;
            }
            return statusCharge;
        }, threadPoolExecutor);
    }

    /**
     * 更新充电订单
     *
     * @param chargeOrder     数据中心获得的充电数据
     * @param userStrokeOrder 充电订单
     * @param userStroke      行程信息
     */
    public void updateUserStrokeOrderCharge(DcOrderDTO chargeOrder, UserStrokeOrder userStrokeOrder, UserStrokeDTO userStroke) {
        UserStrokeOrderDTO userStrokeOrderDTO = userStrokeOrderService.modelToDto(userStrokeOrder);
        final UserStrokeOrderChargeDTO userStrokeOrderCharge = userStrokeOrderChargeService.getByIdDto(userStrokeOrderDTO.getOrderId());
        if (null == userStrokeOrderCharge) {
            throw new ApiException(MessageFormat.format("充电订单不存在,orderId: {0}", userStrokeOrderDTO.getOrderId()));
        }
        if (userStrokeOrderDTO.getPayStatus().equals(DisplayUtil.PAY_STATUS_1)) {
            throw new ApiException(MessageFormat.format("订单已经支付成功,orderId: {0}", userStrokeOrderDTO.getOrderId()));
        }
        if (null != chargeOrder.getTotalMoney()) {
            userStrokeOrderCharge.setTotalAmount(new Money(chargeOrder.getTotalMoney()).getAmount());
        }
        if (null != chargeOrder.getTotalElecMoney()) {
            userStrokeOrderCharge.setElectricityFee(new Money(chargeOrder.getTotalElecMoney()).getAmount());
        }
        if (null != chargeOrder.getTotalPower()) {
            userStrokeOrderCharge.setChargeCapacity(new Money(chargeOrder.getTotalPower()).getAmount());
        }
        if (null != chargeOrder.getTotalSeviceMoney()) {
            userStrokeOrderCharge.setServiceCharge(new Money(chargeOrder.getTotalSeviceMoney()).getAmount());
        }
        if (null != chargeOrder.getStartChargeSeqStat()) {
            userStrokeOrderCharge.setState(chargeOrder.getStartChargeSeqStat());
        }
        if (null != chargeOrder.getSoc()) {
            userStrokeOrderCharge.setSoc(chargeOrder.getSoc());
        }
        userStrokeOrderChargeService.update(userStrokeOrderCharge);

        if (StringUtils.hasLength(chargeOrder.getStartTime())) {
            userStrokeOrderDTO.setStartTime(DateUtil.strToLocalDateTime(chargeOrder.getStartTime()));
        }
        if (StringUtils.hasLength(chargeOrder.getEndTime())) {
            userStrokeOrderDTO.setEndTime(DateUtil.strToLocalDateTime(chargeOrder.getEndTime()));
        }
        if (null != userStrokeOrderCharge.getTotalAmount()) {
            userStrokeOrderDTO.setOnLinePayAmount(userStrokeOrderCharge.getTotalAmount());
            userStrokeOrderDTO.setPayAmount(userStrokeOrderCharge.getTotalAmount());
            userStrokeOrderDTO.setOrderAmount(userStrokeOrderCharge.getTotalAmount());
        }

        userStrokeOrderService.update(userStrokeOrderDTO);

        userStroke.setPayAmount(userStrokeOrderDTO.getPayAmount());

        userStrokeOrderDTO.freeData();
        userStrokeOrderCharge.freeData();
    }

    /**
     * 更新充电订单
     *
     * @param statusCharge    数据中心获得的充电数据
     * @param userStrokeOrder 充电订单
     */
    public void buildUserStrokeOrderCharge(StatusChargeRespDTO statusCharge, UserStrokeOrderDTO userStrokeOrder) {
        final UserStrokeOrderChargeDTO userStrokeOrderCharge = userStrokeOrderChargeService.getByIdDto(userStrokeOrder.getOrderId());
        if (null == userStrokeOrderCharge) {
            throw new ApiException(MessageFormat.format("充电订单不存在,orderId: {0}", userStrokeOrder.getOrderId()));
        }
        if (userStrokeOrder.getPayStatus().equals(DisplayUtil.PAY_STATUS_1)) {
            throw new ApiException(MessageFormat.format("订单已经支付成功,orderId: {0}", userStrokeOrder.getOrderId()));
        }
        if (null != statusCharge.getTotalMoney()) {
            userStrokeOrderCharge.setTotalAmount(new Money(statusCharge.getTotalMoney()).getAmount());
        }
        if (null != statusCharge.getElectricityMoney()) {
            userStrokeOrderCharge.setElectricityFee(new Money(statusCharge.getElectricityMoney()).getAmount());
        }
        if (null != statusCharge.getTotalPower()) {
            userStrokeOrderCharge.setChargeCapacity(new Money(statusCharge.getTotalPower()).getAmount());
        }
        if (null != statusCharge.getServiceMoney()) {
            userStrokeOrderCharge.setServiceCharge(new Money(statusCharge.getServiceMoney()).getAmount());
        }
        if (null != statusCharge.getStartChargeSeqStat()) {
            userStrokeOrderCharge.setState(statusCharge.getStartChargeSeqStat());
        }
        if (StringUtils.hasLength(statusCharge.getStartTime())) {
            userStrokeOrder.setStartTime(DateUtil.strToLocalDateTime(statusCharge.getStartTime()));
        }
        if (StringUtils.hasLength(statusCharge.getEndTime())) {
            userStrokeOrder.setEndTime(DateUtil.strToLocalDateTime(statusCharge.getEndTime()));
        }
        if (null != userStrokeOrderCharge.getTotalAmount()) {
            userStrokeOrder.setOnLinePayAmount(userStrokeOrderCharge.getTotalAmount());
            userStrokeOrder.setPayAmount(userStrokeOrderCharge.getTotalAmount());
            userStrokeOrder.setOrderAmount(userStrokeOrderCharge.getTotalAmount());
        }
        userStrokeOrder.setOrderCharge(userStrokeOrderCharge);
    }

    public UserStrokeOrderDTO createUserStrokeOrderPark(PayInfoDTO payInfoDTO, UserStrokeDTO userStroke) {
        final String payNo = payInfoDTO.getPayNo();
        if (!StringUtils.hasText(payNo)) {
            throw new ApiException("停车订单payNo为空");
        }
        if (!StringUtils.hasLength(payInfoDTO.getLastFee())) {
            throw new ApiException("应缴费金额为空");
        }
        if (!StringUtils.hasLength(payInfoDTO.getInTime())) {
            throw new ApiException("进场时间为空");
        }
        if (!StringUtils.hasLength(payInfoDTO.getLaneCode())) {
            throw new ApiException("车道号为空");
        }
        if (null == payInfoDTO.getStayedTime()) {
            throw new ApiException("停车时间为空");
        }
        final BigDecimal lastFee;
        try {
            lastFee = new BigDecimal(payInfoDTO.getLastFee());
        } catch (Exception e) {
            throw new ApiException("应缴费金额转换失败");
        }
        UserStrokeOrder userStrokeOrder = userStrokeOrderService.getUniqueByThirdPartyOrderId(payNo);
        if (null == userStrokeOrder) {
            userStrokeOrder = new UserStrokeOrder();
            userStrokeOrder.setParkId(userStroke.getParkId());
            userStrokeOrder.setPlateNumber(userStroke.getPlateNumber());
            userStrokeOrder.setSid(userStroke.getSid());
            userStrokeOrder.setUserId(userStroke.getUserId());
            userStrokeOrder.setOrderId(IdWorker.getIdStr());
            userStrokeOrder.setThirdPartyOrderId(payNo);
            userStrokeOrder.setBid(userStrokeOrder.getOrderId());
            userStrokeOrder.setOrderType(DisplayUtil.ORDER_TYPE_1);
            userStrokeOrder.setEtcPay(plateService.etcPay(userStroke.getPlateNumber()));
            userStrokeOrder.setTripType(DisplayUtil.TRIP_TYPE_0);
            userStrokeOrder.setPayStatus(DisplayUtil.PAY_STATUS_0);
            userStrokeOrder.setExtendsFiles(payInfoDTO.getLaneCode());
        } else {
            if (userStrokeOrder.getPayStatus().equals(DisplayUtil.PAY_STATUS_1)) {
                log.error(MessageFormat.format("订单已经支付成功,orderId: {0}", userStrokeOrder.getOrderId()));
                return null;
            }
        }
        userStrokeOrder.setPayAmount(lastFee);
        userStrokeOrder.setOrderAmount(userStrokeOrder.getPayAmount());
        userStrokeOrder.setOnLinePayAmount(userStrokeOrder.getPayAmount());
        userStrokeOrder.setStartTime(DateUtil.strToLocalDateTime(payInfoDTO.getInTime()));
        if (StringUtils.hasLength(payInfoDTO.getOutTime())) {
            userStrokeOrder.setEndTime(DateUtil.strToLocalDateTime(payInfoDTO.getOutTime()));
        } else {
            final LocalDateTime startTime = userStrokeOrder.getStartTime();
            final LocalDateTime endTime = startTime.plusMinutes(payInfoDTO.getStayedTime());
            userStrokeOrder.setEndTime(endTime);
        }
        return userStrokeOrderService.modelToDto(userStrokeOrder);
    }

    /**
     * 新用户注册以后，查询当前用户的车辆是否处于插枪状态
     * 如果是就生成行程订单，让用户在我的行程里面可以看见
     * 然后用户手动点击开始充电
     *
     * @param userId      用户ID
     * @param plateNumber 车牌号
     * @param parkId      停车场
     */
    @Transactional(rollbackFor = Exception.class)
    public void createChargeOrder(String userId, String plateNumber, String parkId) {
        List<String> plateNumberList = new ArrayList<>(3);
        if (StringUtils.hasLength(plateNumber)) {
            if (!userPlateRelationService.checkPlateNumber(userId, plateNumber)) {
                log.error("用户和车牌号不匹配,userId: {},plateNumber： {}", userId, plateNumber);
                throw new ApiException("用户和车牌号不匹配");
            }
            plateNumberList.add(plateNumber);
        } else {
            final List<UserPlateRelation> list = userPlateRelationService.getUserPlateRelationByUserId(userId);
            if (list.isEmpty()) {
                throw new ApiException("当前用户没有绑定车牌号");
            }
            plateNumberList = list.stream().map(UserPlateRelation::getPlateNumber).filter(number -> number.length() > 7).collect(Collectors.toList());
        }
        if (plateNumberList.isEmpty()) {
            throw new ApiException("当前用户没有绑定新能源车牌号");
        }
        boolean doHandle = false;
        for (String number : plateNumberList) {
            if (doHandle) {
                return;
            }
            final ChargeStatusDTO chargeStatusDTO = dcService.status(number);
            if (null == chargeStatusDTO) {
                log.error("根据车牌号查询插枪状态为空，不做处理");
                break;
            }
//        if (!chargeStatusDTO.getParkId().equals(parkId)) {
//            log.error("根据车牌号查询插枪状态,停车场ID不匹配,本方parkId: {},数据中台parkId: {}", parkId, chargeStatusDTO.getParkId());
//            return;
//        }
            final Integer status = chargeStatusDTO.getStatus();
            log.info("根据车牌号查询插枪状态,status:{}", status);
            //只处理2和4的
            if (status.equals(2) || status.equals(4)) {
                UserStrokeDTO query = new UserStrokeDTO();
                query.setUserId(userId);
                final UserStroke userStroke = userStrokeService.getProcessStroke(query);
                query.freeData();
                if (null != userStroke) {
                    boolean b = userStrokeOrderChargeService.notStartCharge(userStroke.getSid());
                    if (b) {
                        return;
                    }
                }
                doHandle = true;
                ChargeBO chargeBO = new ChargeBO().setPlateNumber(number).setParkingId(parkId).setConnectorID(chargeStatusDTO.getConnectorID()).setOperatorID(chargeStatusDTO.getOperatorId()).setStartChargeSeqStat(-1);
                startCharge(chargeBO);
                chargeBO.freeData();
            }
            chargeStatusDTO.freeData();
        }

    }

    private static DcOrderDTO buildChargeBoToDcOrderDTO(ChargeBO chargeBO) {
        DcOrderDTO dcOrderDTO = new DcOrderDTO();
        dcOrderDTO.setStartTime(chargeBO.getStartTime());
        dcOrderDTO.setEndTime(chargeBO.getEndTime());
        dcOrderDTO.setTotalMoney(chargeBO.getTotalMoney().doubleValue());
        dcOrderDTO.setTotalElecMoney(chargeBO.getTotalElecMoney().doubleValue());
        dcOrderDTO.setTotalPower(chargeBO.getTotalPower().doubleValue());
        dcOrderDTO.setTotalSeviceMoney(chargeBO.getTotalSeviceMoney().doubleValue());
        dcOrderDTO.setStartChargeSeq(chargeBO.getStartChargeSeq());
        dcOrderDTO.setStartChargeSeqStat(chargeBO.getStartChargeSeqStat());
        dcOrderDTO.setSoc(chargeBO.getSoc());
        return dcOrderDTO;
    }
}